
format ELF64 executable 3
entry main

include 'util/import64.inc'

RTLD_LAZY = 1
None = 0
AllocNone = 0
False = 0
True = 1
InputOutput = 1
GLX_RENDER_TYPE = 0x8011
GLX_RGBA_BIT = 0x00000001
GLX_DRAWABLE_TYPE = 0x8010
GLX_WINDOW_BIT = 0x00000001
GLX_DOUBLEBUFFER = 5
GLX_RED_SIZE = 8
GLX_GREEN_SIZE = 9
GLX_BLUE_SIZE = 10
GLX_DEPTH_SIZE = 12
GLX_STENCIL_SIZE = 13
KeyPressMask = 1 shl 0
KeyPress = 2
CWBackPixel = 1 shl 1
CWBorderPixel =	1 shl 3
CWEventMask	= 1 shl 11
CWColormap = 1 shl 13
CLOCKS_PER_SEC = 1000000

GL_COLOR_BUFFER_BIT = 0x00004000
GL_VERTEX_PROGRAM_ARB = 0x8620
GL_FRAGMENT_PROGRAM_ARB = 0x8804
GL_PROGRAM_FORMAT_ASCII_ARB = 0x8875
GL_ARRAY_BUFFER = 0x8892
GL_STATIC_DRAW = 0x88E4
GL_BUFFER_GPU_ADDRESS_NV = 0x8F1D
GL_READ_ONLY = 0x88B8
GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV = 0x8F1E
GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV = 0x8F20
GL_FLOAT = 0x1406
GL_FALSE = 0
GL_TRIANGLES = 0x0004

interpreter '/lib64/ld-linux-x86-64.so.2'
needed 'libdl.so.2','libc.so.6','libm.so.6','libX11.so.6'
import \
    printf,exit,sinf,cosf,dlopen,dlsym,clock, \
    XOpenDisplay,XDefaultScreen,XCreateColormap,XRootWindow,XCreateWindow,XMapWindow,XPending,XNextEvent,XStoreName,XInternAtom,XChangeProperty,XMoveWindow,XFlush

macro print_rax {
    mov rdi,str_rax
    mov rsi,rax
    call [printf]
}
macro gl_define_cmd name {
str_#name db `name,0
name dq ?
}
macro gl_load_cmd name {
    mov rdi,str_#name
    call [glXGetProcAddress]
    mov [name],rax
    ;mov rdi,str_s_p
    ;mov rsi,str_#name
    ;mov rdx,rax
    ;call [printf]
}

segment readable executable

main:
    ; open display
    xor edi,edi
    call [XOpenDisplay]
    mov [x_display],rax
    ; get default screen
    mov rdi,[x_display]
    call [XDefaultScreen]
    mov [x_screen],eax
    ; get root window
    mov rdi,[x_display]
    mov esi,[x_screen]
    call [XRootWindow]
    mov [x_root_window],rax
    ; load OpenGL library
    mov rdi,str_libGL
    mov esi,RTLD_LAZY
    call [dlopen]
    mov [gl_lib],rax
    ; load glXGetProcAddress
    mov rdi,[gl_lib]
    mov rsi,str_glXGetProcAddress
    call [dlsym]
    mov [glXGetProcAddress],rax
    ; load GLX functions
    gl_load_cmd glXChooseFBConfig
    gl_load_cmd glXGetVisualFromFBConfig
    gl_load_cmd glXCreateContext
    gl_load_cmd glXMakeCurrent
    gl_load_cmd glXSwapBuffers
    ; get fb configs
    mov rdi,[x_display]
    mov esi,[x_screen]
    mov rdx,glx_fb_attribs
    mov rcx,glx_fb_configs_count
    call [glXChooseFBConfig]
    mov [glx_fb_configs],rax
    ; get visual from the first fb config
    mov rdi,[x_display]
    mov rsi,[glx_fb_configs]
    mov rsi,[rsi]
    call [glXGetVisualFromFBConfig]
    mov [x_visual_info],rax
    ; set window attributes
    mov rdi,[x_display]
    mov rsi,[x_root_window]
    mov rdx,[x_visual_info]
    mov rdx,[rdx]
    mov ecx,AllocNone
    call [XCreateColormap]
    mov [x_win_attribs+96],rax
    mov [x_win_attribs+72],KeyPressMask
    ; create window
    mov rax,[x_visual_info]
    mov rdi,x_win_attribs
    and rsp,0xfffffffffffffff0
    push rdi
    push CWBackPixel+CWBorderPixel+CWColormap+CWEventMask
    push qword [rax+0]
    push InputOutput
    push qword [rax+20]
    push 0
    mov r9,800
    mov r8,800
    mov ecx,0
    mov edx,0
    mov rsi,[x_root_window]
    mov rdi,[x_display]
    call [XCreateWindow]
    add rsp,48
    mov [x_window],rax
    ; map window
    mov rdi,[x_display]
    mov rsi,[x_window]
    call [XMapWindow]
    ; set window name
    mov rdi,[x_display]
    mov rsi,[x_window]
    mov rdx,win_name
    call [XStoreName]
    ; remove window borders
    mov rdi,[x_display]
    mov rsi,str_motif_wm_hints
    mov edx,True
    call [XInternAtom]
    mov [x_atom],rax
    print_rax
    push 10
    mov rax,motif_wm_hints
    push rax
    mov r9d,0
    mov r8d,32
    mov rcx,[x_atom]
    mov rdx,[x_atom]
    mov rsi,[x_window]
    mov rdi,[x_display]
    call [XChangeProperty]
    add rsp,16
    ; move window
    mov rdi,[x_display]
    mov rsi,[x_window]
    mov edx,10
    mov ecx,10
    call [XMoveWindow]
    call [XFlush]
    ; create context
    mov rdi,[x_display]
    mov rsi,[x_visual_info]
    xor edx,edx
    mov ecx,True
    call [glXCreateContext]
    mov [gl_ctx],rax
    ; make current
    mov rdi,[x_display]
    mov rsi,[x_window]
    mov rdx,[gl_ctx]
    call [glXMakeCurrent]
    ; load GL commands
    gl_load_cmd glClear
    gl_load_cmd glGenProgramsARB
    gl_load_cmd glBindProgramARB
    gl_load_cmd glGenBuffers
    gl_load_cmd glBindBuffer
    gl_load_cmd glEnable
    gl_load_cmd glDrawArrays
    gl_load_cmd glBufferData
    gl_load_cmd glBufferAddressRangeNV
    gl_load_cmd glVertexAttribFormatNV
    gl_load_cmd glGetBufferParameterui64vNV
    gl_load_cmd glMakeBufferResidentNV
    gl_load_cmd glEnableVertexAttribArray
    gl_load_cmd glEnableClientState
    gl_load_cmd glProgramLocalParameters4fvEXT
    gl_load_cmd glGetError
    gl_load_cmd glGetString
    gl_load_cmd glProgramStringARB
    ; gen programs
    mov edi,2
    mov rsi,program
    call [glGenProgramsARB]
    ; vertex program
    mov edi,GL_VERTEX_PROGRAM_ARB
    mov esi,[program+0]
    call [glBindProgramARB]
    mov edi,GL_VERTEX_PROGRAM_ARB
    mov esi,GL_PROGRAM_FORMAT_ASCII_ARB
    mov edx,[src_vp_len]
    mov rcx,src_vp
    call [glProgramStringARB]
    ; fragment program
    mov edi,GL_FRAGMENT_PROGRAM_ARB
    mov esi,[program+4]
    call [glBindProgramARB]
    mov edi,GL_FRAGMENT_PROGRAM_ARB
    mov esi,GL_PROGRAM_FORMAT_ASCII_ARB
    mov edx,[src_fp_len]
    mov rcx,src_fp
    call [glProgramStringARB]
    ; vbo
    mov edi,1
    mov rsi,vertex_buffer
    call [glGenBuffers]
    mov edi,GL_ARRAY_BUFFER
    mov esi,[vertex_buffer]
    call [glBindBuffer]
    mov edi,GL_ARRAY_BUFFER
    mov esi,60
    mov rdx,vertex_data
    mov ecx,GL_STATIC_DRAW
    call [glBufferData]
    mov edi,GL_ARRAY_BUFFER
    mov esi,GL_BUFFER_GPU_ADDRESS_NV
    mov rdx,vertex_buffer_addr
    call [glGetBufferParameterui64vNV]
    mov edi,GL_ARRAY_BUFFER
    mov esi,GL_READ_ONLY
    call [glMakeBufferResidentNV]
    ; state
    mov edi,GL_VERTEX_PROGRAM_ARB
    call [glEnable]
    mov edi,GL_FRAGMENT_PROGRAM_ARB
    call [glEnable]
    call [glGetError]
    print_rax
    ; enter main loop
      main_loop:
    mov rdi,[x_display]
    call [XPending]
    test eax,eax
    jz render
    mov rdi,[x_display]
    mov rsi,x_event
    call [XNextEvent]
    cmp dword [x_event+0],KeyPress
    je quit
    jmp main_loop
      render:
    ; get time
    xor edi,edi
    call [clock]
    cvtsi2ss xmm0,eax
    mov eax,CLOCKS_PER_SEC
    cvtsi2ss xmm1,eax
    divss xmm0,xmm1
    movd [time],xmm0
    ; compute rotation matrix
    call [sinf]
    pxor xmm1,xmm1
    subss xmm1,xmm0
    movd [matrix+4],xmm1
    movd [matrix+16],xmm0
    movd xmm0,[time]
    call [cosf]
    movd [matrix+0],xmm0
    movd [matrix+20],xmm0
    ; clear
    mov edi,GL_COLOR_BUFFER_BIT
    call [glClear]
    ; bind programs
    mov edi,GL_VERTEX_PROGRAM_ARB
    mov esi,[program+0]
    call [glBindProgramARB]
    mov edi,GL_FRAGMENT_PROGRAM_ARB
    mov esi,[program+4]
    call [glBindProgramARB]
    ; set rotation matrix
    mov edi,GL_VERTEX_PROGRAM_ARB
    mov esi,0
    mov edx,4
    mov rcx,matrix
    call [glProgramLocalParameters4fvEXT]
    ; enable vertex arrays
    mov edi,GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV
    call [glEnableClientState]
    mov edi,0
    call [glEnableVertexAttribArray]
    mov edi,1
    call [glEnableVertexAttribArray]
    ; set vertex array format
    mov edi,0
    mov esi,2
    mov edx,GL_FLOAT
    mov ecx,GL_FALSE
    mov r8,20
    call [glVertexAttribFormatNV]
    mov edi,1
    mov esi,3
    mov edx,GL_FLOAT
    mov ecx,GL_FALSE
    mov r8,20
    call [glVertexAttribFormatNV]
    ; set vertex array adress
    mov edi,GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV
    mov esi,0
    mov rdx,[vertex_buffer_addr]
    mov ecx,60
    call [glBufferAddressRangeNV]
    mov edi,GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV
    mov esi,1
    mov rdx,[vertex_buffer_addr]
    add rdx,8
    mov ecx,60-8
    call [glBufferAddressRangeNV]
    ; draw
    mov edi,GL_TRIANGLES
    mov esi,0
    mov edx,3
    call [glDrawArrays]
    ; swap
    mov rdi,[x_display]
    mov rsi,[x_window]
    call [glXSwapBuffers]
    jmp main_loop
      quit:
    ; terminate process
    xor edi,edi
    call [exit]

segment readable writeable

NL equ db 10,

src_vp db '!!NVvp4.0'
NL 'FLOAT PARAM rot[4] = { program.local[0..3] };'
NL 'main:'
NL '    DP4.F result.position.x, rot[0], vertex.attrib[0];'
NL '    DP4.F result.position.y, rot[1], vertex.attrib[0];'
NL '    DP4.F result.position.z, rot[2], vertex.attrib[0];'
NL '    DP4.F result.position.w, rot[3], vertex.attrib[0];'
NL '    MOV.F result.attrib[0], vertex.attrib[1];'
NL '    RET;'
NL 'END',0
src_vp_len dd $-src_vp-1
src_fp db '!!NVfp4.0'
NL 'main:'
NL '    MOV.F result.color, fragment.attrib[0];'
NL '    RET;'
NL 'END',0
src_fp_len dd $-src_fp-1

program dd 0,0
vertex_buffer dd 0
vertex_buffer_addr dq 0
vertex_data dd -0.7,-0.7,1.0,0.0,0.0, 0.7,-0.7,0.0,1.0,0.0, 0.0,0.7,0.0,0.0,1.0

win_name db 'eneida :: triangle',0
time dd 0

str_libGL db 'libGL.so.1',0
str_rax db 'rax: %p',0xa,0
str_s_p db '%s : %p',0xa,0
str_motif_wm_hints db '_MOTIF_WM_HINTS',0

motif_wm_hints dq 2,0,0,0,0

x_display dq 0
x_screen dd 0
         dd 0
x_window dq 0
x_root_window dq 0
x_win_attribs dq 14 dup(0)
x_visual_info dq 0
x_event dq 16 dup(0)
x_atom dq 0

glx_fb_configs_count dd 0
glx_fb_configs dq 0
glx_fb_attribs dd \
    GLX_RENDER_TYPE,GLX_RGBA_BIT, \
    GLX_DRAWABLE_TYPE,GLX_WINDOW_BIT, \
    GLX_DOUBLEBUFFER,True, \
    GLX_RED_SIZE,8, \
    GLX_GREEN_SIZE,8, \
    GLX_BLUE_SIZE,8, \
    GLX_DEPTH_SIZE,24, \
    GLX_STENCIL_SIZE,8, \
    None

gl_lib dq ?
gl_ctx dq ?

gl_define_cmd glXGetProcAddress
gl_define_cmd glXChooseFBConfig
gl_define_cmd glXGetVisualFromFBConfig
gl_define_cmd glXCreateContext
gl_define_cmd glXMakeCurrent
gl_define_cmd glXSwapBuffers

gl_define_cmd glClear
gl_define_cmd glGenProgramsARB
gl_define_cmd glBindProgramARB
gl_define_cmd glGenBuffers
gl_define_cmd glBindBuffer
gl_define_cmd glEnable
gl_define_cmd glDrawArrays
gl_define_cmd glBufferData
gl_define_cmd glBufferAddressRangeNV
gl_define_cmd glVertexAttribFormatNV
gl_define_cmd glGetBufferParameterui64vNV
gl_define_cmd glMakeBufferResidentNV
gl_define_cmd glEnableVertexAttribArray
gl_define_cmd glEnableClientState
gl_define_cmd glProgramLocalParameters4fvEXT
gl_define_cmd glGetError
gl_define_cmd glGetString
gl_define_cmd glProgramStringARB

align 16
matrix dd 1.0,0.0,0.0,0.0, 0.0,1.0,0.0,0.0, 0.0,0.0,1.0,0.0, 0.0,0.0,0.0,1.0
